package com.scalefuture.gmemcached;

import com.sun.grizzly.Context;
import com.sun.grizzly.ProtocolFilter;
import com.sun.grizzly.ProtocolParser;
import com.sun.grizzly.util.OutputWriter;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.util.ArrayList;

import net.sf.ehcache.Element;

public class ProcessorFilter implements ProtocolFilter {

    public boolean execute(Context context) throws IOException {
        Object msg = context.getAttribute(ProtocolParser.MESSAGE);
        //TODO TCP,UDP
//        if (context.getProtocol() == Controller.Protocol.TCP) { // TCP case
        SelectableChannel channel = context.getSelectionKey().channel();
        if (msg != null) {
            if (msg instanceof String) {
                OutputWriter.flushChannel(channel, ByteBuffer.wrap(((String) msg).getBytes()));
            }
            if (msg instanceof Command) {
                Command cmd = (Command) msg;

                if (cmd.getCmd().equalsIgnoreCase("set")) {
                    GMemcached.map.put(new Element(cmd.getKey(), cmd));
                    OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.STORED.getBytes()));
                } else if (cmd.getCmd().equalsIgnoreCase("add")) {
                    if (GMemcached.map.get(cmd.getKey())!=null) {
                        OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.NOT_STORED.getBytes()));
                    } else {
                        GMemcached.map.put(new Element(cmd.getKey(), cmd));
                        OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.STORED.getBytes()));
                    }
                } else if (cmd.getCmd().equalsIgnoreCase("replace")) {
                    if (GMemcached.map.get(cmd.getKey())!=null) {
                        GMemcached.map.put(new Element(cmd.getKey(), cmd));
                        OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.STORED.getBytes()));
                    } else {
                        OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.NOT_STORED.getBytes()));
                    }
                } else if (cmd.getCmd().equalsIgnoreCase("get") || cmd.getCmd().equalsIgnoreCase("gets")) {
                    StringBuffer sb = new StringBuffer();
                    ArrayList keys = cmd.getArgs();
                    for (int i = 0; i < keys.size(); i++) {
                        String key = (String) keys.get(i);
                        if (GMemcached.map.get(key)!=null) {
                            Command vcmd = (Command)((Element)GMemcached.map.get(key)).getObjectValue() ;
                            sb.append("VALUE ");
                            sb.append(key);
                            sb.append(" ");
                            sb.append(vcmd.getFlags());
                            sb.append(" ");
                            sb.append(vcmd.getData_length());
                            sb.append("\r\n");
                            sb.append(new String(vcmd.getData()));
                            sb.append("\r\n");
                        }
                    }
                    sb.append("END\r\n");
                    OutputWriter.flushChannel(channel, ByteBuffer.wrap(sb.toString().getBytes()));
                } else if (cmd.getCmd().equalsIgnoreCase("delete")) {
                    if (GMemcached.map.get(cmd.getArgs().get(0))!=null) {
                        GMemcached.map.remove(cmd.getArgs().get(0));
                        OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.DELETED.getBytes()));
                    } else {
                        OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.NOT_FOUND.getBytes()));
                    }
                } else if (cmd.getCmd().equalsIgnoreCase("incr") || cmd.getCmd().equalsIgnoreCase("decr")) {
                    if (GMemcached.map.get(cmd.getArgs().get(0))!=null) {
                        Command vcmd = (Command) ((Element)GMemcached.map.get(cmd.getArgs().get(0))).getObjectValue();
                        BigDecimal v = new BigDecimal("0");
                        BigDecimal vv = new BigDecimal("0");
                        try {
                            v = new BigDecimal(new String(vcmd.getData()));
                        } catch (Exception e) {
                        }
                        if (v.compareTo(new BigDecimal("0")) < 0) {
                            v = new BigDecimal("0");
                        }

                        try {
                            vv = new BigDecimal((String) cmd.getArgs().get(1));
                        } catch (Exception e) {
                        }
                        if (vv.compareTo(new BigDecimal("0")) < 0) {
                            vv = new BigDecimal("0");
                        }
                        if (cmd.getCmd().equalsIgnoreCase("incr")) v = v.add(vv);
                        if (cmd.getCmd().equalsIgnoreCase("decr")) {
                            v = v.subtract(vv);
                            if (v.compareTo(new BigDecimal("0")) < 0) {
                                v = new BigDecimal("0");
                            }
                        }
                        vcmd.setData(v.toPlainString().getBytes());
                        vcmd.setData_length(v.toPlainString().getBytes().length);
                        GMemcached.map.put(new Element(vcmd.getKey(), vcmd));

                        OutputWriter.flushChannel(channel, ByteBuffer.wrap((v.toPlainString() + "\r\n").getBytes()));
                    } else {
                        OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.NOT_FOUND.getBytes()));
                    }
                } else if (cmd.getCmd().equalsIgnoreCase("verbosity")) {
                    OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.OK.getBytes()));
                } else if (cmd.getCmd().equalsIgnoreCase("stat")) {
                    //TODO
                    OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.OK.getBytes()));
                    //STAT <name> <value>\r\n
                    //STAT <name> <value>\r\n
                    //END\r\n
                } else if (cmd.getCmd().equalsIgnoreCase("flush_all")) {
                    GMemcached.map.removeAll();
                    OutputWriter.flushChannel(channel, ByteBuffer.wrap(GMemcached.OK.getBytes()));
                } else if (cmd.getCmd().equalsIgnoreCase("version")) {
                    OutputWriter.flushChannel(channel, ByteBuffer.wrap(("VERSION " + GMemcached.VERSION + "\r\n").getBytes()));
                } else if (cmd.getCmd().equalsIgnoreCase("quit")) {
                    channel.close();
                }
            }
        }
        return false;
    }

    public boolean postExecute(Context context) throws IOException {
        return true;
    }
}
